/*
 * Copyright Aristool AG Switzerland
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); 
 * you may not use this file except in compliance with the License. 
 * You may obtain a copy of the License at 
 * 
 * http://www.apache.org/licenses/LICENSE-2.0 
 * 
 * Unless required by applicable law or agreed to in writing, software 
 * distributed under the License is distributed on an "AS IS" BASIS, 
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
 * See the License for the specific language governing permissions and 
 * limitations under the License.
 */
package org.opprua.tidy.util;

import java.io.*;

/**
 * TODO: add Java doc
 *
 * Prepared for first commit: 15.04.2007
 *
 * @author Lin Li
 */
public class CodePrint extends PrintWriter {

  /** The indentation String to prepend to printed lines. */
  private String indent = "";

  /** The extendion to indent when indentation increase. */
  private String indentString = "  ";

  /**
   * A boolean specifying whether this CodeWriter should prepend the indentation
   * text to the requested print String.
   */
  private boolean startOfNewLine = true;

  /** The position of the current cursor in the line. */
  private int cursor = 0;

  /**
   * <p>
   * Constructs a CodeWriter with the file name given. If the file, or even some
   * part of the path leading to he file, does not exit, it (they) will be
   * created. The prepend string is repeatedly prepended to the beginning of
   * each line depending the current indentation level of the writer.
   * </p>
   * 
   * @param filename
   *          the path to the file to be written
   * @param prepend
   *          the elements to fill the indentation space
   */
  public static CodePrint create(String filename, String prepend) {
    try {
      FileUtil.prepare(filename);
      PrintWriter f = new PrintWriter(new FileWriter(filename));
      return new CodePrint(f, prepend);
    } catch (Throwable e) {
      throw new Error("Failed to open file for code writer " + filename, e);
    }
  }

  /**
   * <p>
   * Constructs a CodeWriter with default indentation filler (<tt>"  "</tt>).
   * </p>
   * 
   * @param filename
   *          the path to the file to be written
   * @see #create(String, String)
   */
  public static CodePrint create(String filename) {
    return create(filename, "  ");
  }

  /**
   * <p>
   * Constructs a CodeWriter with a ready PrintWriter and default indentation
   * filler (<tt>"  "</tt>).
   * </p>
   * 
   * @param w
   *          the readily opened PrintWriter
   * @see #create(String, String)
   */
  public static CodePrint create(PrintWriter w) {
    try {
      return new CodePrint(w, "  ");
    } catch (Throwable e) {
      throw new Error("Failed to access filewriter " + w, e);
    }
  }

  private CodePrint(PrintWriter f, String prepend) throws Exception {
    super(f, true);
    this.indentString = prepend;
  }

  /**
   * @see java.io.PrintWriter#println(Object)
   */
  public void println(String string) {
    print(string);
    println();
  }

  /**
   * @see java.io.PrintWriter#print(Object)
   */
  public void print(String string) {
    if (startOfNewLine) {
      super.print(indent);
      cursor = indent.length();
    }
    cursor += string.length();
    startOfNewLine = false;

    super.print(string);
  }

  /**
   * @see java.io.PrintWriter#print(boolean)
   */
  public void print(boolean b) {
    print(String.valueOf(b));
  }

  /**
   * @see java.io.PrintWriter#print(char)
   */
  public void print(char c) {
    print(String.valueOf(c));
  }

  /**
   * @see java.io.PrintWriter#print(char[])
   */
  public void print(char[] s) {
    print(String.valueOf(s));
  }

  /**
   * @see java.io.PrintWriter#print(double)
   */
  public void print(double d) {
    print(String.valueOf(d));
  }

  /**
   * @see java.io.PrintWriter#print(float)
   */
  public void print(float f) {
    print(String.valueOf(f));
  }

  /**
   * @see java.io.PrintWriter#print(int)
   */
  public void print(int i) {
    print(String.valueOf(i));
  }

  /**
   * @see java.io.PrintWriter#print(long)
   */
  public void print(long l) {
    print(String.valueOf(l));
  }

  /**
   * @see java.io.PrintWriter#println(boolean)
   */
  public void println(boolean x) {
    println(String.valueOf(x));
  }

  /**
   * @see java.io.PrintWriter#println(char)
   */
  public void println(char x) {
    println(String.valueOf(x));
  }

  /**
   * @see java.io.PrintWriter#println(char[])
   */
  public void println(char[] x) {
    println(String.valueOf(x));
  }

  /**
   * @see java.io.PrintWriter#println(double)
   */
  public void println(double x) {
    println(String.valueOf(x));
  }

  /**
   * @see java.io.PrintWriter#println(float)
   */
  public void println(float x) {
    println(String.valueOf(x));
  }

  /**
   * @see java.io.PrintWriter#println(int)
   */
  public void println(int x) {
    println(String.valueOf(x));
  }

  /**
   * @see java.io.PrintWriter#println(long)
   */
  public void println(long x) {
    println(String.valueOf(x));
  }

  /**
   * <p>
   * end this line
   * </p>
   */
  public void println() {
    super.println();
    startOfNewLine = true;
    cursor = 0;
  }

  /**
   * <p>
   * Copy a file verbatim into the file generated. The indentation levels are
   * not effective for the data from that file.
   * </p>
   * 
   * @param file
   *          name of the file to be inserted here.
   */
  public void insertFile(String file) {
    try {
      FileReader fr = new FileReader(file);
      char[] buf = new char[1024];
      int read = fr.read(buf);
      while (read > 0) {
        write(buf, 0, read);
        read = fr.read(buf);
      }
      fr.close();
    } catch (Throwable e) {
      throw new Error("Failed to copy file " + file, e);
    }
    startOfNewLine = true;
    cursor = 0;
  }

  /**
   * <p>
   * Flags that code should be indented one level more than it is now.
   * </p>
   */
  public void einruecken() {
    indent = indent + indentString;
  }

  /**
   * <p>
   * Flags that code should be indented one level less than it is now.
   * </p>
   */
  public void ausruecken() {
    if (indent.length() >= indentString.length()) {
      indent = indent.substring(indentString.length());
    }
  }

  /**
   * <p>
   * print a quoted string
   * </p>
   */
  public void printQuoted(String string) {
    print("\"" + string + "\"");
  }

  /**
   * <p>
   * print a string with a padding space in front. If the line is already too
   * long, the padding string turns into a new line and some prepended spaces
   * </p>
   */
  public void printPadded(String string) {
    if (string.length() == 0) {
      return;
    }
    if (!startOfNewLine) {
      if (cursor > 80) {
        println();
        print("        ");
      } else {
        print(" ");
      }
    }
    print(string);
  }

  /**
   * <p>
   * Let's test this thing.
   * </p>
   */
  public static void main(String[] args) throws IOException {

    CodePrint out = CodePrint.create("C:\\Temp\\codeWriterTest.txt");
    out.println("public class HelloWorld {");
    out.einruecken();
    out.print("public ");
    out.println("static void main(String[] args) {");
    out.einruecken();
    out.print("System.out.print(\"");
    out.println("Hello world!\");");
    out.ausruecken();
    out.println("}");
    out.ausruecken();
    out.println("}");
  }
}
